#pragma once
#include "EventHandler.hpp"
#include "Epoll.hpp"
#include "Common.hpp"
#include <functional>

class ConnectSocketEH;
using service_t = std::function<std::string(std::string&)>;

// 连接套接字事件处理器
class ConnectSocketEH : public EventHandler
{
public:
    ConnectSocketEH(std::shared_ptr<TCPConnectSocket> connect_socket, service_t service, Epoll *monitor = nullptr)
        : EventHandler(monitor)
        , _connect_socket(std::move(connect_socket))
        , _service(service)
    {
        SetNonBlock(_connect_socket->SockFd());
        SetEvents(EPOLLET | EPOLLIN);
    }
    void HandleRecv() override
    {
        int n = 0;
        std::string tmp;
        while(true)
        {
            if((n = _connect_socket->Receive(tmp)) > 0)
            {
                LOG(LogLevel::INFO) << "收到新的消息: " << tmp;
                _recv_buffer += tmp;
            }
            else if(n == 0)
            {
                LOG(LogLevel::INFO) << "[" << _connect_socket->Addr().Info() << "]连接已断开! ";
                _monitor->DelEventHandler(_monitor->GetHandler(Fd()));
                break;
            }
            else if(errno == EAGAIN || errno == EWOULDBLOCK)
                break;
            else if(errno == EINTR)
                continue;
            else
            {
                LOG(LogLevel::ERROR) << "ConnectSocketEH::HandleRecv: 获取数据出错! ";
                HandleExce();
                break;
            }
        }

        if(!_recv_buffer.empty())
            _send_buffer = _service(_recv_buffer);
        
        if(!_send_buffer.empty())
        {
            HandleSend(); // 最佳实践
            // 或者开启写事件关心
            // _monitor->ModEventHandler(_monitor->GetHandler(Fd()), Events() | EPOLLOUT);
        }
    }
    void HandleSend() override
    {
        while(true)
        {
            int n = _connect_socket->Send(_send_buffer);
            if(n > 0)
            {
                // 未发完，删掉已发部分继续发
                _send_buffer.erase(0, n);
            }
            else if(n == 0)
            {
                // 发完
                break;
            }
            else
            {
                if(errno == EAGAIN || errno == EWOULDBLOCK)
                    break;
                else if(errno == EINTR)
                    continue;
                else
                {
                    LOG(LogLevel::ERROR) << "ConnectSocketEH::HandleSend: 发送失败! ";
                    HandleExce();
                    break;
                }
            }
        }

        if(!_send_buffer.empty())
        {
            // 写条件不满足, 开启对写事件的关心
            SetEvents(Events() | EPOLLOUT);
            _monitor->ModEventHandler(_monitor->GetHandler(Fd()), Events());
        }
        else
        {
            // 数据已写完, 关闭对写事件的关心
            SetEvents(Events() & ~EPOLLOUT);
            _monitor->ModEventHandler(_monitor->GetHandler(Fd()), Events());
        }
    }
    void HandleExce() override
    {
        _monitor->DelEventHandler(_monitor->GetHandler(Fd()));
    }
    int Fd() override
    {
        return _connect_socket->SockFd();
    }
    ~ConnectSocketEH() {}

private:
    std::shared_ptr<TCPConnectSocket> _connect_socket;
    service_t _service;
};

// 监听套接字事件处理器
class ListenSocketEH : public EventHandler
{
public:
    ListenSocketEH(in_port_t port, service_t service, Epoll *monitor = nullptr)
        : EventHandler(monitor)
        , _service(service)
    {
        _listen_socket = std::make_shared<TCPListenSocket>(port);
        SetNonBlock(_listen_socket->SockFd());
        SetEvents(EPOLLET | EPOLLIN);
    }
    void HandleRecv() override
    {
        std::shared_ptr<TCPConnectSocket> connect_socket = nullptr;
        while (true)
        {
            if(connect_socket = _listen_socket->Accept())
            {
                std::shared_ptr<ConnectSocketEH> cs_eh = std::make_shared<ConnectSocketEH>(connect_socket, _service, _monitor);
                _monitor->AddEventHandler(cs_eh, EPOLLIN | EPOLLET);
            }
            else if(errno == EAGAIN || errno == EWOULDBLOCK)
                break;
            else if(errno == EINTR)
                continue;
            else
            {
                LOG(LogLevel::ERROR) << "ListenSocketEH::HandleRecv: 建立新连接出错! ";
                break;
            }
        }
    }
    int Fd() override
    {
        return _listen_socket->SockFd();
    }
    ~ListenSocketEH() {}

private:
    std::shared_ptr<TCPListenSocket> _listen_socket;
    service_t _service;
};